package com.easydict.util;

import com.easydict.annotation.EasyDict;
import com.easydict.config.DictProvider;
import com.easydict.config.FieldDictionary;
import com.easydict.resolver.DelegatingDictionaryResolver;
import com.easydict.spi.DictionaryResolutionContext;
import com.easydict.spi.DictionaryResolver;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 数据字典手动转换工具类
 * @author EasyDict
 * @version 1.0.1
 * @since 1.0.0
 */
@Component
public class EasyDictUtil {
  
    private static final Map<Class<?>, BeanGenerator> beanGeneraMapEasy =  new HashMap<>();
    private static final Map<Class<?>, List<FieldDictionary>> dictionaryMap = new HashMap<>();

    @Autowired(required = false)
    private DictProvider dictProvider;

    private DictionaryResolver dictionaryResolver;

    private void initDictionaryResolver() {
        if (dictionaryResolver == null && dictProvider != null) {
            dictionaryResolver = new DelegatingDictionaryResolver(dictProvider);
        }
    }

    public <T> List<T> listConverter(List<T> list){
        if (CollectionUtils.isEmpty(list)) return list;
        Class<?> entityClass = list.get(0).getClass();
  
        if (beanGeneraMapEasy.get(entityClass) == null) processData(entityClass);
  
        if(dictionaryMap.get(entityClass).size() == 0) return list;
  
        return getCopyList(list);
  
    }  
  
    private <T> List<T> getCopyList(List<T> list) {
        List<T> copyList = new ArrayList<>(list.size());  
        for (T item : list) {
            Class<?> targetClazz = item.getClass();
            Object copyItem = beanGeneraMapEasy.get(targetClazz).create();
            BeanUtils.copyProperties(item, copyItem);
            BeanMap beanMap = BeanMap.create(copyItem);
            for (FieldDictionary fieldDic : dictionaryMap.get(targetClazz)) {  
                Method method = ReflectionUtils.findMethod(targetClazz, "get" + fieldDic.getFieldName());  
                String fieldValue = null;  
                try {  
                    fieldValue = method != null ? (String) method.invoke(item) : "";
                } catch (Exception ignored) {
                }
                String dictName = getDictName(fieldDic.getDicValue(), fieldValue);
                beanMap.put(fieldDic.getFieldNameDic(), dictName);
            }  
            copyList.add((T)copyItem);
        }  
        return copyList;  
    }



    private static void processData(Class<?> firstClass) {
        BeanGenerator beanGenerator = new BeanGenerator();
        beanGenerator.setSuperclass(firstClass);  
        beanGeneraMapEasy.put(firstClass, beanGenerator);
        ArrayList<FieldDictionary> fieldDicList = new ArrayList<>();
        dictionaryMap.put(firstClass, fieldDicList);
        Field[] allFields = getAllFields(firstClass);
        for (Field field : allFields) {  
            String fieldName = field.getName();
            EasyDict annotation = field.getAnnotation(EasyDict.class);
            if (annotation != null && StringUtils.isNotBlank(annotation.dictType())) {
                String filedNameDic = fieldName + "Dic";
                beanGenerator.addProperty(filedNameDic, String.class);
                FieldDictionary fieldDic = new FieldDictionary();  
                fieldDic.setFieldName(fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
                fieldDic.setFieldNameDic(filedNameDic);
                fieldDic.setDicValue(annotation.dictType());
                fieldDicList.add(fieldDic);  
            }  
        }  
    }  
  
  

    private static Field[] getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null && clazz != Object.class) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields.toArray(new Field[0]);
    }

    private String getDictName(String typeCode, String fieldValue) {
        initDictionaryResolver();
        if (StringUtils.isBlank(fieldValue)) {
            return null;
        }
        if (dictionaryResolver == null) {
            return fieldValue + "[未配置字典提供者]";
        }
        try {
            DictionaryResolutionContext context = DictionaryResolutionContext.builder()
                    .typeCode(typeCode)
                    .rawValue(fieldValue)
                    .sourceType(String.class)
                    .fieldName("manual_conversion")
                    .attribute("source", "DictToValueByGenerateUtil")
                    .build();

            Optional<String> result = dictionaryResolver.resolve(context);
            return result.orElse(fieldValue);
        } catch (Exception e) {
            return fieldValue + "[解析异常]";
        }
    }

    public static String convertDictValue(String typeCode, String fieldValue, DictProvider dictProvider) {
        if (StringUtils.isBlank(fieldValue) || dictProvider == null) {
            return fieldValue;
        }

        try {
            // 直接使用字典提供者进行转换
            String result = dictProvider.getDictName(typeCode, fieldValue);
            return result != null ? result : fieldValue;
        } catch (Exception e) {
            return fieldValue + "[转换失败]";
        }
    }

    public <T> T convertSingleObject(T obj) {
        if (obj == null) {
            return null;
        }

        List<T> list = new ArrayList<>();
        list.add(obj);
        List<T> result = listConverter(list);

        return result.isEmpty() ? obj : result.get(0);
    }

}